import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by IntelliJ IDEA.
 * @Author : Ding
 * @create 2022/4/14 19:51
 * 【简单】
 * 给定一个整数数组 nums和一个整数目标值 target，请你在该数组中找出和为目标值 target的那两个整数，并返回它们的数组下标。
 * 你可以假设每种输入只会对应一个答案。但是，数组中同一个元素在答案里不能重复出现。
 * 你可以按任意顺序返回答案。
 *
 * 示例 1：---------------------------------------------------------
 * 输入：nums = [2,7,11,15], target = 9
 * 输出：[0,1]
 * 解释：因为 nums[0] + nums[1] == 9 ，返回 [0, 1] 。
 *
 * 示例 2：---------------------------------------------------------
 * 输入：nums = [3,2,4], target = 6
 * 输出：[1,2]
 *
 * 示例 3：---------------------------------------------------------
 * 输入：nums = [3,3], target = 6
 * 输出：[0,1]
 *
 * 提示：
 * ------ 2 <= nums.length <= 10^4
 * ------ -10^9 <= nums[i] <= 10^9
 * ------ -10^9 <= target <= 10^9
 * ------ 只会存在一个有效答案
 *
 * 进阶：你可以想出一个时间复杂度小于 O(n2) 的算法吗？
 *
 * 链接：https://leetcode-cn.com/problems/two-sum
 *
 */
public class _0001_两数之和_简单 {
    public static long START_TIME = 0;
    public static long END_TIME = 0;

    public static void main(String[] args) {
        START_TIME = System.currentTimeMillis();
        //调用部分↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
        int[] nums = {3,2,4,6,8,9,12,17,21,22,23,24};
        int target = 28;
        System.err.println(Arrays.toString(new _0001_两数之和_简单().twoSum3(nums, target)));
        //调用部分↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
        END_TIME = System.currentTimeMillis();
        System.err.println("运行时间：" + (END_TIME - START_TIME) + "ms");
    }

    /**
     * 官方解法-改良嵌套for循环，复杂度为O(n2)，48~60ms
     * 可以避免重复，最高效的用循环得出结果
     * @param nums
     * @param target
     * @return
     */
    public int[] twoSum2(int[] nums,int target){
        int n = nums.length;
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {
                //第二层遍历是基于第一层遍历，+1，空间上类似于直角在右上角的直角三角形▽
                //由于是两层循环，所以复杂度是on2
                if (i != j && nums[i] + nums[j] == target){
                    return new int[]{i,j};
                }
            }
        }
        return new int[0];
    }

    /**
     * 最快解法-Java哈希表（可以把复杂度降低到o(n)，1~3ms）
     * @param nums
     * @param target
     * @return
     */
    public int[] twoSum3(int[] nums,int target){
        Map<Integer,Integer> hashmap=new HashMap<>();
        for(int i=0;i<nums.length;i++){
            //作差，从空开始，看列表中是否有包含一个key
            //这样的key的value满足目标值减去当前一层遍历的值的差
            //如果不满足，把这个put进去，再进入下一个循环
            //由于是但层循环，所以复杂度为On
            if(hashmap.containsKey(target-nums[i])){
                return new int[]{i,hashmap.get(target-nums[i])};
            }else{
                hashmap.put(nums[i],i);
            }
        }
        return new int[0];
    }

    /**
     * 暴力解法-最硬嵌套for循环
     * @param nums
     * @param target
     * @return
     */
    public int[] twoSum(int[] nums,int target){
        int[] ret = new int[2];
        for (int i = 0; i < nums.length; i++) {
            for (int j = 0; j < nums.length; j++) {
                if (i != j && nums[i] + nums[j] == target){
                    ret[0] = i;
                    ret[1] = j;
                    break;
                }
            }
        }
        return ret;
    }



}
